package m3f.io;

import java.util.ArrayList;

import m3f.matrix.SparseVector;
import ncsa.hdf.hdf5lib.H5;
import ncsa.hdf.hdf5lib.HDF5Constants;
import ncsa.hdf.hdf5lib.exceptions.HDF5Exception;
import ncsa.hdf.hdf5lib.exceptions.HDF5LibraryException;
import ncsa.hdf.object.h5.H5CompoundDS;
import ncsa.hdf.object.h5.H5File;

public class Hdf5MatrixReader extends MatrixReader {

	private static String FILENAME;
	private static String DATASETNAME = "features";
	H5CompoundDS metadata;
	private int rows;
	private int columns;
	private int featuresLEN = 4096;
	private int RANK = 1;
	private int FIELD_SIZE = 4;
	private int typeField = HDF5Constants.H5T_NATIVE_FLOAT;
	private String nameColumn="featuresL7"; 
	private int startR;
	private int readLines;
	


	@Override
	public void start(String filename) {
		this.FILENAME = filename;
		H5File h5file = new H5File(this.FILENAME, H5File.READ);

		try {
			metadata = (H5CompoundDS) h5file.get(DATASETNAME);
			metadata.init();
			rows = metadata.getHeight();// Number of examples
			columns = featuresLEN;
			startR = 0;
			readLines = 0;
			h5file.close();

		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(-1);
		}

	}

	@Override
	public int getMatrixRows() {
		return rows;
	}

	@Override
	public int getMatrixColumns() {
		return columns;
	}

	@Override
	public ArrayList<SparseVector> readVectors(int numVectors) {
		ArrayList<SparseVector> vectors = new ArrayList<SparseVector>();
		//long start = System.currentTimeMillis();
		float features[] = new float[columns];
		int fid, array_dt, space, type, dataset, i, j, k, rank = -1, mrank = -1, fspace = -1, mspace = -1, status = -1;

		long[] dima = { columns };
		long[] mdims = new long[1];
		long[] dims = new long[1];
		long[] maxdims = new long[1];
		long[] offset = new long[1];
		long[] count = new long[1];
		
		int vectorCounter;
		offset[0] = startR;
		count[0] = 1;
		mdims[0] = 1;
		mrank = 1;
		
		try {
			fid = H5.H5Fopen(FILENAME, HDF5Constants.H5F_ACC_RDWR, HDF5Constants.H5P_DEFAULT);
			System.out.println("File ID returned by H5Fopen() : " + fid + " \n");

			dataset = H5.H5Dopen(fid, DATASETNAME, HDF5Constants.H5P_DEFAULT);
			System.out.println("Dataset" + DATASETNAME + "opened:" + dataset + " \n");

			type = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, columns*FIELD_SIZE);
			System.out.println("H5Tcreate returns:" + type + "\n");

			array_dt = H5.H5Tarray_create(typeField, RANK, dima);
			System.out.println("H5Tarray_create() returns : " + array_dt + "\n");

			status = H5.H5Tinsert(type, nameColumn, 0, array_dt);
			System.out.println("Status returned by H5Tinsert() : " + status + "\n");

			System.out.println("Reading the rows. \n");

			mspace = H5.H5Screate_simple(mrank, mdims, null);
			System.out.println("mspace : " + mspace + "\n");
			
			fspace = H5.H5Dget_space(dataset);
			
			vectorCounter = 0;
			k = startR;
            while(vectorCounter < numVectors && (readLines <= rows)){               	
				offset[0] = k;
				status = H5.H5Sselect_hyperslab(fspace, HDF5Constants.H5S_SELECT_SET, offset, null,	count, null);
				status = H5.H5Dread(dataset, type, mspace, fspace, HDF5Constants.H5P_DEFAULT, features);
				vectors.add(parseRow(features));
				vectorCounter++;
				k++;
				readLines++;
            }
            if(readLines == rows){
            	status = H5.H5Sclose(fspace);
     			status = H5.H5Dclose(dataset);
     		    System.out.println("Status returned by H5Dclose() : \n" + status);

     		    status = H5.H5Tclose (type);
     		    System.out.println("Status returned by H5Tclose() : \n" + status);  
     		  
     		    status = H5.H5Tclose (array_dt);
     		    System.out.println("Status returned by H5Tclose() :  \n" + status);  

     		    status = H5.H5Fclose(fid);
     		    System.out.println("Status returned by H5Fclose() :  \n" + status);
            }

		} catch (HDF5LibraryException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (HDF5Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        startR = readLines;
		return vectors;
	}
	private SparseVector parseRow(float[] row){
		
		if(row.length != columns ){
			System.err.println("Error: Reading the file " + FILENAME + "." +
					"Wrong number of columns");
			System.exit(1);
		}
		SparseVector v = new SparseVector();
		for(int i = 0; i < row.length; i++){			
			v.setQuick(i, row[i]);
		}		        
		if(normalizing()) v.normalizeL1();
		return v;
	}
	public static void main(String[] args) {
		String filename = "imageClefFeatures6.h5";
		MatrixReader mr = new Hdf5MatrixReader();
		mr.normalizeVectors(true);
		mr.start(filename);
		SparseVector s = null;

		ArrayList<SparseVector> vectors = mr.readVectors(2);
		
		for (int j = 0; j < vectors.size(); j++) {
			s = vectors.get(j);
			System.out.println("Vector " + j + "\n");
			for (int i = 0; i < 5; i++) {
				System.out.println(s.get(i) + "\n");
			}
		}
		vectors = mr.readVectors(1);
		for (int j = 0; j < vectors.size(); j++) {
			s = vectors.get(j);
			System.out.println("Vector " + j + "\n");
			for (int i = 0; i < 5; i++) {
				System.out.println(s.get(i) + "\n");
			}
		}
	}
}
